Aller au contenu principal
Version: 6.5

Gestion du store

La création du store et son accès depuis l’extérieur est géré par la librairie core. Le store corresponds au stockage des informations récupérées depuis les appels API. Le lien entre l’état du store et les données récupérées depuis les appels API est réalisé grâce à des reducers. Ces reducers sont des fonctions asynchrones qui permettent d’effectuer des requêtes et de dispatcher les données dans les différents objets du store.

La librairie core fournit une fonction handlerApiCall permettant de simplifier l’écriture des fonctions asynchrones des reducers en encapsulant la gestion des erreurs mais également la gestion du succès avec la récupération des données.

interface ApiHandlerProps {
fetchFunction: (data: any) => Promise<any>; // Fonction API
data: any; // Données pour la requête
action: string; // Description de l'action en cours d'exécution
getState: () => any; // Fonction permettant d'avoir l'état du state
responseOptions?: {
showToast?: boolean; // Affichage d'un toast en cas de succès
isArrayResponse?: boolean; // La réponse attendue est un tableau ou non
returnTotal?: boolean; // Renvoie le nombre total d'éléments respectant la requête dans la base
returnResponseMessage?: boolean; // Renvoie la réponse de la requête en plus des données
};
errorOptions?: {
showErrorToast?: boolean; // Affiche un toast lors d'une erreur sur la requête
errorTracing?: boolean; // Crée un traceback lors d'une erreur sur la requête
};
}

export const handlerApiCall = ({
fetchFunction,
data,
action,
getState,
responseOptions= {
showToast: false,
isArrayResponse: false,
returnTotal: false,
returnResponseMessage: false,
},
errorOptions = {showErrorToast: true, errorTracing: true},
}: ApiHandlerProps)

Lors de la création de la fonction asynchrone, il est important de respecter la nomenclature suivante pour la création du type : *<nom du slice>/<nom de la fonction>*

Il faut ensuite construire un slice permettant permettant d’indiquer le comportant à adopter dans les différents états des requêtes (pending, rejected ou fulfilled). Afin de pouvoir accéder à l’état du store pour ce slice, il faut l’exporter puis exporter le reducer ansi créé pour pouvoir l’ajouter à l’export du module.

À titre d’exemple, le code suivant correspond à la création d’un reducer pour récupérer une liste d’unités depuis l’instance web de l’ERP.

import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import {handlerApiCall} from '@axelor/aos-mobile-core';
import {searchUnit} from '../api/unit-api';

export const fetchUnit = createAsyncThunk(
'unit/fetchUnit',
async function (data = {}, {getState}) {
return handlerApiCall({
fetchFunction: searchUnit,
data,
action: 'fetch units',
getState,
responseOptions: {isArrayResponse: true},
});
},
);

const initialState = {
loadingUnit: false,
unitList: [],
};

const unitSlice = createSlice({
name: 'unit',
initialState,
extraReducers: builder => {
builder.addCase(fetchUnit.pending, state => {
state.loadingUnit = true;
});
builder.addCase(fetchUnit.fulfilled, (state, action) => {
state.loadingUnit = false;
state.unitList = action.payload;
});
},
});

export const unitReducer = unitSlice.reducer;

Dans le fichier index du dossier features contenant l’ensemble des slices du module, il faut ensuite exporter ce reducer sous un nom plus simple permettant par la suite d’accéder à son state :

Capture d’écran du 2023-03-21 09-21-01.png

export {catalogReducer as catalog} from './catalogSlice';
export {clientReducer as client} from './clientSlice';
export {contactReducer as contact} from './contactSlice';
export {eventReducer as event} from './eventSlice';
export {functionReducer as function} from './functionSlice';
export {leadReducer as lead} from './leadSlice';
export {opportunityReducer as opportunity} from './opportunitySlice';
export {partnerReducer as partner} from './partnerSlice';
export {prospectReducer as prospect} from './prospectSlice';

Une fois les reducers exportés sous un nouveau nom, il faut ensuite les exporter avec le module dans l’attribut dédiés pour que le module core puisse les ajouter au store.

import {Module} from '@axelor/aos-mobile-core';
...
import * as myModuleReducers from './features';

const myModule : Module {
name: "my-module-key";
title: "MyModule_Name";
subtitle: "MyModule_SubName";
icon: ...;
menus: {...};
screens: {...};
translations: {...},
reducers: {...myModuleReducers},
models: {...}
}

Une fois les exports finis, il est donc possible d’accéder au contenu du store depuis les écrans ou les composants grâce au hook du package core en indiquant le reducer à utiliser et les attributs du state correspondant à récupérer : useSelector . Le composant sera mis à jour à chaque changement de valeur du state.

import {useSelector} from '@axelor/aos-mobile-core';

...

const {stateProps} = useSelector((state: any) => state.reducerName);

Le package core fournit également un second hook useDispatch qui permet de récupérer une fonction pour réaliser les actions définies dans les reducers.

import {useDispatch} from '@axelor/aos-mobile-core';
import {actionName} from '../../../../features/...Slice';

...

const dispatch = useDispatch();

...

const realizeAction = useCallback(
() => {
dispatch(actionName(data));
},
[dispatch, data],
);